<?php


use App\Http\Model\Hint;
use App\Lib\Snowflake\Snowflake;
use Illuminate\Support\Facades\Log;

//生成验证码
function randomkeys()
{
    return rand(100000, 999999);
}

//生成uuid
function makeUuid($length)
{
    $pattern = '1234567890abcdefghijklmnopqrstuvwxyz
               ABCDEFGHIJKLOMNOPQRSTUVWXYZ';
    $key = '';
    for ($i = 0; $i < $length; $i++) {
        $key .= $pattern[mt_rand(0, 35)];    //生成php随机数
    }
    return $key;
}

//生成随机唯一token
function getRoundToken()
{
    $token = md5(uniqid(md5(microtime(true)), true));
    return $token;
}

/*
//从cookie中获取token
function getTokenFCookie(){
    if(isset($_COOKIE['user_token'])){
        return $_COOKIE['user_token'];
    }else{
        return '';
    }
}
*/


function init_redis_session()
{
    ini_set("session.save_handler", "redis");
    ini_set("session.save_path", sprintf("tcp://%s:%s?database=%s&auth=%s", env('REDIS_HOST'), env('REDIS_PORT'), env('REDIS_SESSION_DB'), env('REDIS_PASSWORD')));
    session_start();
}

//写入日志 todo
function write_log($dirName, $request_desc = 'log', $requestData)
{
    $dirPath = storage_path() . '/apiLogs';
    if (!is_dir($dirPath)) {
        mkdir($dirPath, 0777, true);
    }
    if (is_array($requestData)) {
        $requestData = json_encode($requestData, JSON_UNESCAPED_UNICODE);
    }

    try {
        file_put_contents($dirPath . '/' . $dirName . '-' . date('Y-m-d') . '.log', '[' . date('Y-m-d H:i:s') . ']' . ' ' . $request_desc . ' ' . $requestData . PHP_EOL, FILE_APPEND);
    } catch (\Exception $e) {
    }
}

/**
 * 发起 server 请求
 * @param $action
 * @param $params
 * @param string $contentType
 * @param string $httpMethod
 * @param array $httpHeader 外部可自定义header, 默认为空数组
 * @return mixed
 */
function curl_request($action, $params, $contentType = 'urlencoded', $httpMethod = 'POST', $httpHeader = [])
{
    $ch = curl_init();
    if ($httpMethod == 'POST' && $contentType == 'urlencoded') {
        $httpHeader[] = 'Content-Type:application/x-www-form-urlencoded';
        curl_setopt($ch, CURLOPT_POSTFIELDS, build_query($params));
    }
    if ($httpMethod == 'POST' && $contentType == 'json') {
        $httpHeader[] = 'Content-Type:application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
    }
    if ($httpMethod == 'POST' && $contentType == 'plain') {
        $httpHeader[] = 'Content-Type:text/plain';
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    }
    if ($httpMethod == 'GET' && $contentType == 'urlencoded') {
        $action .= strpos($action, '?') === false ? '?' : '&';
        $action .= build_query($params);
    }
    curl_setopt($ch, CURLOPT_URL, $action);
    curl_setopt($ch, CURLOPT_POST, $httpMethod == 'POST');
    curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //处理http证书问题
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // dd(curl_getinfo($ch));
    $ret = curl_exec($ch);
    if (false === $ret) {
        $ret = curl_errno($ch);
    }
    curl_close($ch);
    return $ret;
}

/**
 * 重写实现 http_build_query 提交实现(同名key)key=val1&key=val2
 * @param array $formData 数据数组
 * @param string $numericPrefix 数字索引时附加的Key前缀
 * @param string $argSeparator 参数分隔符(默认为&)
 * @param string $prefixKey Key 数组参数，实现同名方式调用接口
 * @return string
 */
function build_query($formData, $numericPrefix = '', $argSeparator = '&', $prefixKey = '')
{
    $str = '';
    if (empty($formData)) {
        return $str;
    }
    foreach ($formData as $key => $val) {
        if (!is_array($val)) {
            $str .= $argSeparator;
            if ($prefixKey === '') {
                if (is_int($key)) {
                    $str .= $numericPrefix;
                }
                $str .= urlencode($key) . '=' . urlencode($val);
            } else {
                $str .= urlencode($prefixKey) . '=' . urlencode($val);
            }
        } else {
            if ($prefixKey == '') {
                $prefixKey .= $key;
            }
            if (isset($val[0]) && is_array($val[0])) {
                $arr = array();
                $arr[$key] = $val[0];
                $str .= $argSeparator . http_build_query($arr);
            } else {
                $str .= $argSeparator . build_query($val, $numericPrefix, $argSeparator, $prefixKey);
            }
            $prefixKey = '';
        }
    }
    return substr($str, strlen($argSeparator));
}

//Redis 锁 type 1:手动解锁 2：超时解锁
function redis_lock($key, $lockExpire = 10)
{
    $lockKey = 'lock:' . $key;

    $lockValue = time() + $lockExpire;

    $ret = \Illuminate\Support\Facades\Redis::set($lockKey, $lockValue, 'nx', 'ex', $lockExpire);
    if (!$ret) {
        return false;
    }
    //\Illuminate\Support\Facades\Redis::expire($lockKey, $lockExpire);
    return true;

}

//Redis 解锁
function redis_unlock($key)
{
    $lockKey = 'lock:' . $key;
    $ret = \Illuminate\Support\Facades\Redis::del($lockKey);
    return $ret;
}


//redis 锁次数
function redis_num_lock($key, $lockExpire = 10, $num = 10)
{
    $lockKey = 'lock:' . $key;

    $ret = \Illuminate\Support\Facades\Redis::INCR($lockKey);

    if ($ret > $num) {
        return false;
    }

    if ($ret == 1) {
        \Illuminate\Support\Facades\Redis::expire($lockKey, $lockExpire);
    }
    return true;

}

//redis 解锁次数
function redis_num_unlock($key)
{
    $lockKey = 'lock:' . $key;
    $ret = \Illuminate\Support\Facades\Redis::del($lockKey);
    return $ret;
}


//充值订单号
function create_recharge_order_sn()
{
    return date('ymdhis') . date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}

//根据经纬度和半径计算出范围
function calcScope($lat, $lng, $radius)
{
    $degree = (24901 * 1609) / 360.0;
    $dpmLat = 1 / $degree;

    $radiusLat = $dpmLat * $radius;//m
    $minLat = $lat - $radiusLat;
    $maxLat = $lat + $radiusLat;

    $mpdLng = $degree * cos($lat * (M_PI / 180));
    $dpmLng = 1 / $mpdLng;
    $radiusLng = $dpmLng * $radius;
    $minLng = $lng - $radiusLng;
    $maxLng = $lng + $radiusLng;

    $scope = array(
        'minLat' => $minLat,
        'maxLat' => $maxLat,
        'minLng' => $minLng,
        'maxLng' => $maxLng
    );
    return $scope;
}

//获取两个经纬度之间的距离
function calcDistance($lat1, $lng1, $lat2, $lng2)
{
    $lat1 = doubleval($lat1);
    $lng1 = doubleval($lng1);
    $lat2 = doubleval($lat2);
    $lng2 = doubleval($lng2);

    $theta = $lng1 - $lng2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    $dist = acos($dist);
    $dist = rad2deg($dist);
    $miles = $dist * 60 * 1.1515;
    return ($miles * 1.609344);//km
}

/**
 * 生成可访问的image url
 * @param $image
 * @return string
 */
function build_image($image)
{
    if (empty($image)) {
        return "";
    }

    if (strtolower(substr($image, 0, 4)) == "http") {
        return $image;
    }
    if(strtolower(substr($image ,-4)) == 'svga'){
        return getPicDomain() . $image;
    }
    return getPicDomain() . $image;
//    return getPicDomain() . $image . '!default.png';
}

/**压缩图片
 * @param $image
 * @return string
 */
function build_image_small($image)
{
    if (empty($image)) {
        return "";
    }

    if (strtolower(substr($image, 0, 4)) == "http") {
        return $image;
    }
    return getPicDomain() . $image . '!default.png';
//    return getPicDomain() . $image . '!small.png';
}

/**压缩合适比例图片
 * @param $images
 * @param $adapter
 * @return string
 */
function build_adapt_images($images ,$adapter){
    if (empty($images)) {
        return "";
    }
    if(is_array($images)){
        $data = [];
        foreach ($images as $k=>$v){
            if (strtolower(substr($v, 0, 4)) == "http"){
                $data[] = $v;
            }else{
                $data[] = getPicDomain() . $v.'?x-oss-process=image/resize,w_'.intval($adapter).',m_lfit';
            }
        }
    }else{
        $data = '';
        if (strtolower(substr($images, 0, 4)) == "http") {
            $data = $images;
        }else{
            $data = getPicDomain() . $images.'?x-oss-process=image/resize,w_'.intval($adapter).',m_lfit';
        }
    }
    return $data;
}
/**
 * 生成可访问url
 * @param $url
 * @return string
 */
function build_url($url)
{
    if (empty($url)) {
        return "";
    }

    if (strtolower(substr($url, 0, 4)) == "http") {
        return $url;
    }
    return getPicDomain() . $url;
}


function hide_string($str, $top_len = 3, $tail_len = 4)
{
    if (empty($str)) {
        return "";
    }
    $len = mb_strlen($str);
    $tmp = mb_substr($str, 0, $top_len);
    $tmp1 = mb_substr($str, $len - $tail_len, $tail_len);
    $tmp2 = '';
    for ($i = 0; $i < $len - $top_len - $tail_len; $i++) {
        $tmp2 = $tmp2 . '*';
    }
    $str = $tmp . $tmp2 . $tmp1;
    return $str;
}

/**
 * 获取客户端IP
 * @return string
 */
function client_ip()
{
    if (isset($_SERVER['HTTP_ALI_CDN_REAL_IP']) && $_SERVER['HTTP_ALI_CDN_REAL_IP'] && strcasecmp($_SERVER['HTTP_ALI_CDN_REAL_IP'], 'unknown')) {
        $ip = $_SERVER['HTTP_ALI_CDN_REAL_IP'];
    } elseif (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
        $ip = getenv('HTTP_CLIENT_IP');
    } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
        $ip = getenv('REMOTE_ADDR');
    } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    $res = preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
    return $res;
}

/**
 * @param $user_id
 * @return string
 */
function createCode(int $user_id)
{
    $user_id += 45000;
    static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
    $num = $user_id;
    $code = '';
    while ($num > 0) {
        $mod = $num % 35;
        $num = ($num - $mod) / 35;
        $code = $source_string[$mod] . $code;
    }
    if (empty($code[3]))
        $code = str_pad($code, 4, '0', STR_PAD_LEFT);
    return $code;
}

/**
 * @param $code
 * @return float|int
 */
function decode(string $code)
{
    static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
    if (strrpos($code, '0') !== false)
        $code = substr($code, strrpos($code, '0') + 1);
    $len = strlen($code);
    $code = strrev($code);
    $num = 0;
    for ($i = 0; $i < $len; $i++) {
        $num += strpos($source_string, $code[$i]) * pow(35, $i);
    }
    $num -= 45000;
    return $num;
}

function get_remote_addr()
{
    $ip = "unknown";
    if (getenv("HTTP_CLIENT_IP")) {
        $ip = getenv("HTTP_CLIENT_IP");
    } elseif (getenv("HTTP_X_FORWARDED_FOR")) {
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    } elseif (getenv("REMOTE_ADDR")) {
        $ip = getenv("REMOTE_ADDR");
    }
    return $ip;
}


/**
 * 按几率返回数组下标
 * @param $pdf [0.1,0.2,0.3,0.4] 精度到小数后6位, 并且和要为1.0
 * @return int
 */
function aliasMethodRand($pdf)
{
    $d = $pdf;
    $sum = round(array_sum($d));
    if ($sum != 1.0) {
        return null;
    }
    $multiple = 1000000;
    $inc = 0;
    $rand = mt_rand(1, $multiple * $sum);
    foreach ($d as $k => $v) {
        $d[$k] = $inc + $d[$k] * $multiple;
        if ($rand <= $d[$k]) {
            return $k;
        }
        $inc = $d[$k];
    }
    return null;
}


/**
 * 按数量返还数组下标
 * @param $arrNum
 * @return int|null|string
 */
function aliasMethodRandNum($arrNum)
{
    $sum = array_sum($arrNum);
    $rand = mt_rand(1, $sum);
    $inc = 0;
    foreach ($arrNum as $k => $v) {
        $inc = $inc + $v;
        if ($inc >= $rand) {
            return $k;
        }
    }
    return null;
}


function filterUUID($subject)
{
    if (!preg_match("/^\d*$/", $subject)) return false;
    // *AAA*
    if (preg_match("/^\d*?(\d)\\1\\1\d*?$/", $subject)) return true;

    // *[66|77|88|99] 尾号
    if (preg_match("/^\d*?(66|77|88|99)$/", $subject)) return true;

    // *AABB*
    if (preg_match("/^\d*?(\d)\\1(?!\\1)(\d)\\2\d*?$/", $subject)) return true;

    // *ABAB*
    if (preg_match("/^\d*((\d)(?!\\1)(\d))\\1\d*$/", $subject, $matches)) return true;

    // *ABC*
    if (preg_match("/^\d*?(123|234|345|456|567|678|789|987|876|765|654|543|432|321)\d*?$/", $subject)) return true;

    // *ABCABC*
//        if(preg_match("/^\d*?((\d)(?!\\1)(\d)(?!\\2)(\d))\\1\d*?$/", $subject)) return true;
    if (preg_match("/^\d*?((\d)(\d)(\d))\\1\d*?$/", $subject)) return true;

    // *ABCDABCD*
    if (preg_match("/^\d*?((\d)(\d)(\d)(\d))\\1\d*?$/", $subject)) return true;

    // *[1314|520|521|168|518|918]*
    if (preg_match("/^\d*?(1314|520|521|168|518|918)\d*?$/", $subject)) return true;

    // 四位生日未号
    if (preg_match("/^\d*?((0[1,2,3,4,5,6,7,8,9]|10|11|12)([0,1,2]\d|30|31|32))$/", $subject)) return true;

    // 年开头
    if (preg_match("/^(20[0,1,2,3]\d)\d*?$/", $subject)) return true;

    // 年结尾
    if (preg_match("/^\d*?(20[0,1,2,3]\d)$/", $subject)) return true;

    return false;
}

/**
 * CURL请求 GET/POST
 * */
function curlRequest($url, $data = null, $body = false, $header = [], $timeout = 10, $json = false)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

    if (!empty($header)) {
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    }

    if (!empty($data)) {
        $hadFile = false;
        if (is_array($data) && isset($data['media'])) {
            /**
             * 支持文件上传
             */
            if (class_exists('\CURLFile')) {
                curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
                foreach ($data as $key => $value) {
                    if (isPostHasFile($value)) {
                        $data[$key] = new \CURLFile(realpath(ltrim($value, '@')));
                        $hadFile = true;
                    }
                }
            }
            /*elseif (defined('CURLOPT_SAFE_UPLOAD')) {
                if (isPostHasFile()) {
                    curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false);
                    $hadFile = true;
                }
            }*/
        }
        if ($json) {
            $data = json_encode($data);
        } else {
            $data = (!$hadFile && is_array($data)) ? http_build_query($data) : $data;
        }
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }

    if ($body) {
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_NOBODY, 0);// 只取body
    }

    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $output = curl_exec($curl);
    if (false === $output) {
        $ret = curl_errno($curl);
        write_log('curlRequest','curlError', ['url' => $url,'data' => $data,'header'=>$header,'errorInfo' => $ret]);
    }
    $httpInfo = curl_getinfo($curl);
    curl_close($curl);
    if ($body) {
        return [
            'body' => $output,
            'header' => $httpInfo,
        ];
    } else {
        return $output;
    }
}

/**
 * CURL 检测文件是否存在
 * */
function isPostHasFile($value)
{
    if (is_string($value) && strpos($value, '@') === 0 && is_file(realpath(ltrim($value, '@')))) {
        return true;
    }
    return false;
}


/**
 * 身份证获取年纪
 * @param $idcard
 * @return bool|false|string
 */
function getAgeByIdcard($idcard)
{
    $year = substr($idcard, 6, 4);
    $monthDay = substr($idcard, 10, 4);

    $age = date('Y') - $year;
    if ($monthDay > date('md')) {
        $age--;
    }
    return $age;
}

/**
 * 将剩余时间秒数 转化为天小时分秒（两时间戳相减得到相差时间的秒数，然后转化成X天X小时X分X秒）
 * */
function secondConvert($second)
{
    $day = floor($second / (3600 * 24));
    $second = $second % (3600 * 24);//除去整天之后剩余的时间
    $hour = floor($second / 3600);
    $second = $second % 3600;//除去整小时之后剩余的时间
    $minute = floor($second / 60);
    $second = $second % 60;//除去整分钟之后剩余的时间
    return [
        'day' => $day,
        'hour' => $hour,
        'minute' => $minute,
        'second' => $second,
    ];
}

/**
 * 冒泡排序：降序
 * */
function bubbleSort(&$array)
{
    $count = count($array);
    for ($i = 0; $i < $count - 1; $i++) {
        for ($j = 0; $j < $count - 1 - $i; $j++) {
            if ($array[$j] < $array[$j + 1]) {
                $temp = $array[$j];
                $array[$j] = $array[$j + 1];
                $array[$j + 1] = $temp;
            }
        }
    }
}

/**
 * 字符过滤 只保留【中英文/数字/下划线】
 * */
function filterString($str)
{
    preg_match_all('/[\x{4e00}-\x{9fff}a-zA-Z0-9_]+/u', $str, $matches);
    $str = join('', $matches[0]);
    return $str;
}

// 过滤掉emoji表情
function filterEmoji($str)
{
    $str = preg_replace_callback(    //执行一个正则表达式搜索并且使用一个回调进行替换
        '/./u',
        function (array $match) {
            return strlen($match[0]) >= 4 ? '' : $match[0];
        },
        $str);

    return $str;
}

/**
 * 引用算法
 *
 * @param array $array 数据
 * @param string $fieldId 定义字段ID
 * @param string $fieldPid 定义字段父类ID
 * @return array
 * */
function quoteTree($array, $fieldId = 'id', $fieldPid = 'pid')
{
    $items = [];
    foreach ($array as $value) {
        $items[$value[$fieldId]] = $value;
    }

    $tree = [];
    foreach ($items as $key => $value) {
        if (isset($items[$value[$fieldPid]])) {
            $items[$value[$fieldPid]]['sub_item'][] = &$items[$key];
        } else {
            $tree[] = &$items[$key];
        }
    }
    return $tree;
}

/**
 * 数组根据某字段进行分组
 * @param array $dataArr 需要分组的数据
 * @param string $keyStr 分组依据
 * @return array
 */
function dataGroup(array $dataArr, string $keyStr): array
{
    $newArr = [];
    foreach ($dataArr as $k => $val) {    //数据根据日期分组
        $newArr[$val[$keyStr]][] = $val;
    }
    return $newArr;
}


/**
 * 检测虚拟手机号
 * @param $phone
 */
function checkVmPhone($phone)
{
    $head = substr($phone, 0, 3);
    $head2 = substr($phone, 0, 2);
    if ($head2 == '19') {
        return true;
    }
    if ($head == '170') {
        return true;
    }
    if ($head == '171') {
        return true;
    }
    if ($head == '163') {
        return true;
    }
    if ($head == '165') {
        return true;
    }
    if ($head == '167') {
        return true;
    }
    if ($head == '131') {
        return true;
    }
    if ($head == '132') {
        return true;
    }
    return false;
}


function aliasInit($name, $data)
{
    ini_set('max_execution_time', '0');
    ini_set("memory_limit", "-1");
    //$redis = Registry::get('redis');
    $tab = [];
    foreach ($data as $k => $v) {
        for ($i = 0; $i < $v; $i++) {
            $tab[] = $k;
        }
    }
    shuffle($tab);
    \Illuminate\Support\Facades\Redis::multi();
    \Illuminate\Support\Facades\Redis::del($name . ':ALIAS:' . '0');
    \Illuminate\Support\Facades\Redis::del($name . ':ALIAS:' . '1');
    \Illuminate\Support\Facades\Redis::del($name . ':ALIAS:' . 'KEYNAME');
    foreach ($tab as $v) {
        \Illuminate\Support\Facades\Redis::lpush($name . ':ALIAS:' . '0', $v);
    }
    \Illuminate\Support\Facades\Redis::set($name . ':ALIAS:' . 'KEYNAME', $name . ':ALIAS:' . '0');
    \Illuminate\Support\Facades\Redis::exec();
    return true;
}


function aliasIndex($name)
{
    //$redis = Registry::get('redis');
    $luaStr = "KEYS[5] = KEYS[1] .. '0'
                KEYS[6] = KEYS[1] .. '1'
                KEYS[7] = KEYS[1] .. 'KEYNAME'
                local tmpA = redis.call('get', KEYS[7]);
                if tmpA then
                    KEYS[5] = tmpA
                end
                if  KEYS[5] == KEYS[1] .. '1' then
                    KEYS[6] = KEYS[1] .. '0'
                end
                local val
                if ARGV[1] == '1' then
                    val = redis.call('lpop',KEYS[5])
                else
                    val = redis.call('rpop',KEYS[5])
                end
                if val then
                    redis.call('lpush', KEYS[6], val)
                    return val
                else
                    if ARGV[1] == '1' then
                        val = redis.call('lpop',KEYS[6])
                    else
                        val = redis.call('rpop',KEYS[6])
                    end
                    if val then
                        redis.call('lpush', KEYS[5], val)
                        redis.call('set', KEYS[7], KEYS[6])
                        return val
                    end
                end
                return nil
                ";
    $val = \Illuminate\Support\Facades\Redis::eval($luaStr, 1, $name . ':ALIAS:', mt_rand(0, 1));
    return $val;
}



function aliasSetInit($name, $data)
{
    ini_set('max_execution_time', '0');
    ini_set("memory_limit", "-1");
    //$redis = Registry::get('redis');
    $tab = [];
    $index = 0;
    foreach ($data as $k => $v) {
        for ($i = 0; $i < $v; $i++) {
            $tab[] = $index . '|' . $k;
            $index++;
        }
    }
    //shuffle($tab);
    \Illuminate\Support\Facades\Redis::multi();
    \Illuminate\Support\Facades\Redis::del($name . ':ALIASSET:' . '0');
    \Illuminate\Support\Facades\Redis::del($name . ':ALIASSET:' . '1');
    \Illuminate\Support\Facades\Redis::del($name . ':ALIASSET:' . 'KEYNAME');
    foreach ($tab as $v) {
        \Illuminate\Support\Facades\Redis::sadd($name . ':ALIASSET:' . '0', $v);
    }
    \Illuminate\Support\Facades\Redis::set($name . ':ALIASSET:' . 'KEYNAME', $name . ':ALIASSET:' . '0');
    \Illuminate\Support\Facades\Redis::exec();
    return true;
}



function aliasSetIndex($name)
{
    //$redis = Registry::get('redis');
    $luaStr = "local funname = 'spop'
                KEYS[5] = KEYS[1] .. '0'
                KEYS[6] = KEYS[1] .. '1'
                KEYS[7] = KEYS[1] .. 'KEYNAME'
                local tmpA = redis.call('get', KEYS[7]);
                if tmpA then
                    KEYS[5] = tmpA
                end
                if  KEYS[5] == KEYS[1] .. '1' then
                    KEYS[6] = KEYS[1] .. '0'
                end
                local val = redis.call('spop',KEYS[5])
                if val then
                    redis.call('sadd', KEYS[6], val)
                    return val
                else
                    val = redis.call('spop',KEYS[6])
                    if val then
                        redis.call('sadd', KEYS[5], val)
                        redis.call('set', KEYS[7], KEYS[6])
                        return val
                    end
                end
                return nil
                ";
    $val = \Illuminate\Support\Facades\Redis::eval($luaStr, 1, $name . ':ALIASSET:', mt_rand(0, 1));
    $tmpArr = explode('|', $val);
    return $tmpArr[1];
}


function aliasRandom($data)
{
    $num = array_sum($data);
    $randomNum = mt_rand(1, $num);
    foreach ($data as $k => $v) {
        $randomNum = $randomNum - $v;
        if ($randomNum <= 0) {
            return $k;
        }
    }
    return null;
}


function aliasTagRandom($data, $tag, $size)
{
    $retData = [];
    $oldData = \Illuminate\Support\Facades\Redis::HGETALL($tag . ':ALIASTAG');
    for ($i = 0; $i < $size; $i++) {
        $num = array_sum($oldData);
        if ($num == 0) {
            $oldData = $data;
        }
        $index = aliasRandom($oldData);
        $retData[$index] = ($retData[$index] ?? 0) + 1;
        $oldData[$index] = $oldData[$index] - 1;
    }
    \Illuminate\Support\Facades\Redis::HMSET($tag . ':ALIASTAG', $oldData);
    \Illuminate\Support\Facades\Redis::EXPIRE($tag . ':ALIASTAG', 2592000);
    return $retData;
}

/**
 * 生成11位字符串顺序打乱（1个字母+时间戳打乱顺序）
 * */
function generateRandStr()
{
    $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ';
    $strArray = str_split($str);
    shuffle($strArray);

    // TODO 2023 下半年将失效，请后续开发注意哦！！！！！！
    // TODO 2023 下半年将失效，请后续开发注意哦！！！！！！
    // TODO 2023 下半年将失效，请后续开发注意哦！！！！！！
    // TODO 用户表之存储了11长度char类型，该方法返回了11位字符串将在2023下半年将出现重复情况

    $microTime = microtime(true);
    $microTime = str_replace('.', '', $microTime);
    $microTime = substr($microTime, 2, 10);
    $microTime = str_pad($microTime, 10, '0', STR_PAD_LEFT);
    $str = $strArray[0] . $microTime;
    return $str;

    // $strArray = str_split($str);
    // shuffle($strArray);
    // return implode('', $strArray);
}


/**
 * 获取小数点后的位数
 * @param string $num 小数值
 * @return int
 */
function getFloatLength($num)
{
    $count = 0;
    $floatArr = explode('.', $num);
    if (sizeof($floatArr) > 1) {
        $decimal = end($floatArr);
        $count = strlen($decimal);
    }

    return $count;
}



/**
 * 获取周的开始、结束 日期或时间戳
 * @param int $week 周数 （0=本周，>=1为上周、上上周...，<=-1为下周、下下周...）
 * @param int $timeType 时间类型（0=日期格式 1=时间戳格式）
 * @param string $format 格式
 * @return array
 */
function getWeekTimestamp($week = 0, $timeType = 0, $format = 'Y-m-d')
{
    $wn = date('w') ? date('w') : 7;    // 自然周一至周日，将周日0转换成7

    $startTime = date($format, mktime(0, 0, 0, date('m'), date('d') - $wn + 1 - ($week * 7), date('Y')));
    $endTime = date($format, mktime(23, 59, 59, date('m'), date('d') - $wn + 7 - ($week * 7), date('Y')));

    if ($timeType) {
        $startTime .= ' 00:00:00';
        $endTime .= ' 23:59:59';
        return [strtotime($startTime), strtotime($endTime)];
    }

    return [$startTime, $endTime];
}


/**
 * 获取图片域名
 * @return mixed
 */
function getPicDomain()
{
    // if (isset($_SERVER['HTTP_HOST'])) {
    //     if ($_SERVER['HTTP_HOST'] == 'tutu-api.xwak.cn') {
    //         return env('APP_PIC_DOMAIN_LL18');
    //     }else if($_SERVER['HTTP_HOST'] == 'shengya-api.ytp6j6.cn'){
    //         return env('APP_PIC_DOMAIN_SY');
    //     }else if ($_SERVER['HTTP_HOST'] == 'api.yto9.cn') {
    //         return env('APP_PIC_DOMAIN_LL16');
    //     }
    // }

    return env('APP_PIC_DOMAIN');
}


if (!function_exists('error')) {


    /**
     * @param int $code
     * @param string $errorMsg
     * @param array $data
     * @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\JsonResponse
     */
    function error($code = Hint::ERROR, $errorMsg = '', $data = [])
    {
        $msg = isset(Hint::$Msg[$code]) ? Hint::$Msg[$code] : '服务器异常';
        if ($errorMsg) {
            $msg .= ',' . $errorMsg;
        }

        return response()->json(['code' => $code, 'msg' => $msg, 'data' => $data])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }

}


if (!function_exists('success')) {


    /**
     * @param array $data
     * @param int $code
     * @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\JsonResponse
     */
    function success($data = [], $code = Hint::SUCCESS)
    {
        $msg = isset(Hint::$Msg[$code]) ? Hint::$Msg[$code] : 'SUCCESS';
        return response()->json(['code' => $code, 'msg' => $msg, 'data' => $data])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }

}

if (!function_exists('getKSortSign')) {


    /**
     * @param $secret
     * @param array $data
     * @return string
     */
    function getKSortSign($secret, array $data)
    {
        ksort($data);
        // 对数组的值按key排序
        $params = http_build_query($data);
        // 生成sign
        return md5($params . $secret);

    }
}

/**
 * 输出IP信息
 *
 * @param string $ip IP地址
 * @return array
 * */
function outGetIpInfo($ip = '')
{
    $data = [];

    try {
        if (empty($ip)) {
            $ip = client_ip();
        }

        $url = sprintf('https://ip.taobao.com/outGetIpInfo?ip=%s&accessKey=alibaba-inc', $ip);
        $result = curlRequest($url, null, false, [], 1);
        $result = json_decode($result, true);

        $code = $result['code'] ?? 'fail';
        $resultData = $result['data'] ?? [];
        if ($code === 0 && is_array($resultData) && !empty($resultData)) {
            $data = $resultData;
        }

    } catch (\Exception $e) {

    }

    return $data;
}

/**
 * 校验输出IP地址存在指定地址内
 *
 * @return bool
 * */
function getIpAddressInCountryOrCity()
{
    $outGetIpInfo = outGetIpInfo();
    $checkInCountry = ['中国'];
    $checkInChinaCity = ['北京', '上海', '广州', '深圳'];
    $country = $outGetIpInfo['country'] ?? 'XX';
    $city = $outGetIpInfo['city'] ?? 'XX';

    if (!empty($country)) {
        if (!in_array($country, $checkInCountry)) {
            return false;
        }

        if ($country == '中国') {
            if (!in_array($city, $checkInChinaCity)) {
                return false;
            }
        }

        return true;
    }

    return false;
}

if (!function_exists('msectime')) {
    function msectime() {
        list($msec, $sec) = explode(' ', microtime());
        return (float) sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
    }
}

if (!function_exists('getFullImageUrl')) {
    function getFullImageUrl($imgUrl) {
        return $imgUrl ? getPicDomain() . $imgUrl : '';
    }
}

if(!function_exists('ll_debug')) {
    function ll_debug(string $msg, array $content = []){
        if (env('APP_DEBUG') === true) {
            Log::debug($msg, $content);
        }
    }
}

/**
 * 计算有效天数
 * @param $starTime 起使时间 时间戳
 * @param null $endTime 结束时间 默认当前时间戳
 * @return false|int
 *
 */
if(!function_exists('caclValidDayNum')) {
    function caclValidDayNum($endTime, $starTime = null)
    {
        if ($endTime <= 0) {
            return false;
        }
        if (is_null($starTime)) {
            $starTime = time();
        }
        if ($starTime > $endTime) {
            return false;
        }

        $starDate = date('Y-m-d H:i:s', $starTime);
        $endDate = date('Y-m-d H:i:s', $endTime);
        $days = 0;
        $date1 = date_create($starDate);
        $date2 = date_create($endDate);
        $diff = date_diff($date1, $date2, TRUE);
        if ($diff) {
            $days = $diff->days;
        }

        return $days;
    }
}

/**
 * 从 UA 解析出[软件版本 | APP系统名 | 手机型号 | 渠道商ID]
 * @return array
 */
if(!function_exists('parse_app_UA')) {
    function parse_app_UA()
    {
        $originalUA = [];

        $userAgent = $_SERVER['HTTP_H5_USER_AGENT'] ?? $_SERVER['HTTP_USER_AGENT'] ?? '';
        if (!empty($userAgent)) {
            $originalUA = explode(';', $userAgent);
        }
        //安卓写错了只好这样纠正了
        $version_no = $originalUA[1] ?? '';
        $os_name = $originalUA[2] ?? '';
        if($version_no === "Android" || $version_no === "iPhone") {
            $version_no = $originalUA[2] ?? '';
            $os_name = $originalUA[1] ?? '';
        }

        return [
            'app' => $originalUA[0] ?? 'yyaudio',
            'version_no' => $version_no,
            'os_name' => $os_name,
            'device' => $originalUA[4] ?? '',
            'channel_id' => $originalUA[5] ?? '',
            'guid' => $originalUA[6] ?? ''
        ];
    }
}

/**
 * 验证版本号 当前版本号不小于 最低版本号  true
 *
 */
if(!function_exists('checkVersion')) {
    function checkVersion($min_version)
    {
        // 请更新至v2.4.0版本~
        //版本判断
        $parse_app_UA = parse_app_UA();
        if ($parse_app_UA['version_no'] && (version_compare($parse_app_UA['version_no'], $min_version) >= 0)) {
            return true;
        }
        return false;
    }
}

/**
 * 当前模式-cli模式
 */
if(!function_exists('isCli')) {
    function isCli(){
        return preg_match("/cli/i", php_sapi_name()) ? true : false;
    }
}

if (!function_exists('getCityByIp')) {
    function getCityByIp() {
        $outGetIpInfo = outGetIpInfo();
        return $outGetIpInfo['city'] ?? '';
    }
}

/**
 * 对比两个头像数组中，是否有新头像
 * @param $arr1
 * @param $arr2
 * @return array
 */
function diffPortrait($arr1,$arr2){
    $arr1 = array_map(function ($v){return basename(trim($v));},$arr1);
    $arr2 = array_map(function ($v){return basename(trim($v));},$arr2);
    return array_diff($arr1,$arr2);
}

/**
 * 预处理前置信息并AES加密
 * @param mixed $txt
 * @return string
 */
function preEnAES($code, $data =[], $msg=''){
    // 初始化响应结构
    $format_res = ['code' =>$code,'data' => $data ,'msg'  => $msg];
    $format_json = json_encode($format_res,JSON_UNESCAPED_UNICODE);

    if (isset($_SERVER['HTTP_NOAES']) && $_SERVER['HTTP_NOAES'] === '1') {
        // 直接返回未加密数据
        return $format_json; 
    } else {
        // 执行AES加密
        return enAES($format_json); 
    }
}


/**
 * AES加密
 */
function enAES($txt){
    $key = env('AES_KEY', 'yyaudio202302230');
    return base64_encode(openssl_encrypt($txt, 'AES-128-ECB',$key, OPENSSL_RAW_DATA));
}

/**
 * AES解密
 */
function deAES($txt){
    $key = env('AES_KEY', 'yyaudio202302230');
    $data = base64_decode($txt);
    return openssl_decrypt($data, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
}


/**
 * 校验环境是否执行
 */
function checkAppEnv(){
    $result = false;
    do {
        if(env('APP_ENV') != 'product') {
            return true;
        }
    } while (false);

    return $result;
}


/**
 * 获取URL路径
 */
function getUrlPath($url){
    $parseArr = parse_url($url);
    if(!empty($parseArr['path'])){
        return $parseArr['path'];
    }
    return '';
}



if (!function_exists('probabilityAlgorithm')) {
    /**
     * 概率算法（按几率返回数组下标）
     * @param $pdf id=>概率 精度到小数后4位, 并且和要为1.0
     * @return null|int
     */
    function probabilityAlgorithm($pdf)
    {
        $d = $pdf;
        $sum = round(array_sum($d));
        if ($sum != 1.0) {
            return null;
        }

        $multiple = 10000;
        $inc = 0;
        $rand = mt_rand(1, $multiple * $sum);
        foreach ($d as $k => $v) {
            $d[$k] = $inc + $d[$k] * $multiple;
            if ($rand <= $d[$k]) {
                return $k;
            }

            $inc = $d[$k];
        }

        return null;
    }
}

//根据概率算法算抽到的奖品,无奖品数量设定情况使用
function getRand($proArr, $isNotMax = 1) { //计算中奖概率 
    $rs = ''; //z中奖结果 
    if($isNotMax == 0){
        $minArr = $proArr;
        arsort($minArr); // 将数组按从小到大排序
        $newArr = [];
        foreach($minArr as $k=>$v){
            if(count($newArr) < 6){
                $newArr[$k] = $v;
            }
        }
        $proArr = $newArr;
    }
    write_log('colorGift','彩蛋池子数据', $proArr);
    $proSum = array_sum($proArr); //概率数组的总概率精度 
    //概率数组循环 
    foreach ($proArr as $key => $proCur) { 
        $randNum = mt_rand(1, $proSum); 
        if ($randNum <= $proCur) { 
            $rs = $key; 
            break; 
        } else { 
            $proSum -= $proCur; 
        } 
    } 
    unset($proArr); 
    return $rs; 
}

/**
 * 对象转数组
 */
if (!function_exists('objToArray')) {
    function objToArray($document)
    {
        return json_decode(json_encode($document), true);
    }
}

//阿拉伯数字转中文数字
function numberToChinese(int $num)
{
    //节权位的位置
    $unit_section_pos = 0;
    $chn_str = '';
    //单个数字转换用的数组
    $chn_num_char = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
    //节权位转换用的数组
    $chn_unit_section = ["", "万", "亿", "万亿", "亿亿"];
    //节内权位换算的数组
    $chn_unit_char = ["", "十", "百", "千"];
    $need_zero = false;

    if ($num === 0) {
        return $chn_num_char[0];
    }

    //节内换算的闭包
    $section_to_chinese = function ($section) use ($chn_num_char, $chn_unit_char) {
        $chn_str = '';
        //节内的位置
        $unit_pos = 0;
        $zero = true;

        while ($section > 0) {
            $v = $section % 10;
            if ($v === 0) {
                if (!$zero) {
                    $zero = true;
                    $chn_str = $chn_num_char[$v] . $chn_str;
                }
            } else {
                $zero = false;
                $str_ins = $chn_num_char[$v];
                $str_ins .= $chn_unit_char[$unit_pos];
                $chn_str = $str_ins . $chn_str;
            }
            $unit_pos++;
            $section = floor($section / 10);
        }
        return $chn_str;
    };

    while ($num > 0) {
        $section = $num % 10000;
        if ($need_zero) {
            $chn_str = $chn_num_char[0] . $chn_str;
        }
        $str_ins = $section_to_chinese($section);
        $str_ins .= ($section !== 0) ? $chn_unit_section[$unit_section_pos] : $chn_unit_section[0];
        $chn_str = $str_ins . $chn_str;
        $need_zero = ($section < 1000) && ($section > 0);
        $num = floor($num / 10000);
        $unit_section_pos++;
    }

    $search = '一十';
    $replacement = '十';
    //处理含一十开头的（这个可根据需求处理）
    if (mb_substr($chn_str, 0, 2) === $search) {
        $position = strpos($chn_str, $search);
        $chn_str = substr_replace($chn_str, $replacement, $position, strlen($search));
    }

    return $chn_str;
}
